package dk.aiszone.lang.autosource.generatorobjects.helpers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

import dk.aiszone.lang.autosource.generatorobjects.interfaces.BodyContainer;
import dk.aiszone.lang.autosource.generatorobjects.interfaces.SimpleBlockObject;

/**
 * Class used by objects containing a body.
 * 
 * @author Ais
 */
public class BodyObject implements BodyContainer, Cloneable {

    private StringBuilder currentBuilder;
    private StringBuilder currentEndBuilder;
    private List<SimpleBlockObject> endParts = new ArrayList<SimpleBlockObject>();
    private List<SimpleBlockObject> parts = new ArrayList<SimpleBlockObject>();

    /**
     * Constructor for the <code>AbstractBodyContainer</code> object.
     */
    public BodyObject() {
        parts.add(new StringBlock(currentBuilder = new StringBuilder()));
        endParts.add(new StringBlock(currentEndBuilder = new StringBuilder()));
    }

    @Override
    public BodyContainer appendToBody(BodyContainer part) {
        parts.addAll(part.getBodyParts());
        return this;
    }

    @Override
    public BodyContainer appendToBody(boolean part) {
        currentBuilder.append(part);
        return this;
    }

    @Override
    public BodyContainer appendToBody(int part) {
        currentBuilder.append(part);
        return this;
    }

    public BodyContainer appendToBody(SimpleBlockObject part) {
        if (part != null) {
            parts.add(part);
            parts.add(new StringBlock(currentBuilder = new StringBuilder()));
        }
        return this;
    }

    public BodyContainer appendToBody(String part) {
        if (part != null) {
            currentBuilder.append(part);
        }
        return this;
    }

    public BodyContainer appendToBody(StringBuilder part) {
        if (part != null) {
            currentBuilder.append(part);
        }
        return this;
    }

    public BodyContainer appendToBodyEnd(String endPart) {
        if (endPart != null) {
            currentEndBuilder.append(endPart);
        }
        return this;
    }

    @Override
    public Object clone() {
        BodyObject clone = new BodyObject();
        clone.currentBuilder = new StringBuilder(currentBuilder);

        clone.parts = new ArrayList<SimpleBlockObject>();
        for (Iterator<SimpleBlockObject> iterator = parts.iterator(); iterator.hasNext();) {
            clone.parts.add((SimpleBlockObject)iterator.next().clone());
        }

        return clone;
    }

    @Override
    public final boolean equals(Object obj) {
        return EqualsBuilder.reflectionEquals(this, obj);
    }

    /**
     * Retrieve the contents of the <code>AbstractBodyContainer</code>.
     * 
     * @return <code>List</code> of <code>BlockObjects</code> representing the body of the <code>AbstractBodyContainer</code>.
     */
    public List<SimpleBlockObject> getBodyParts() {
        List<SimpleBlockObject> tmp = new ArrayList<SimpleBlockObject>(parts.size() + endParts.size());
        tmp.addAll(parts);
        tmp.addAll(endParts);
        return Collections.unmodifiableList(tmp);
    }

    @Override
    public final int hashCode() {
        return super.hashCode();
    }

    /**
     * Returns true/false indication whether the <code>StaticArea</code> is empty (containing no lines)
     * 
     * @return Is body empty
     */
    public boolean isBodyEmpty() {
        return parts.size() == 1 && ((StringBlock)parts.get(0)).part.length() == 0;
    }

    @Override
    public final String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}